Introduction

Bike share systems provide an eco-friendly transportation option, but one of the bog operational challenge is “re-balancing”, which ensuring bikes are evenly distributed across stations to meet demand. This analysis examines bike prediction for the NY city Bike in Jersey city, which utilize NY city Bike data in April, 2022, along with census and climate information.

By developing a space-time predictive model, the study identifies patterns in bike demand based on socio-economic factors, weather, and commuting trends, particularly near high-demand areas like the Hudson River and Manhattan. These insights aim to improve bike re-balancing strategies, ensuring efficient operations and better user satisfaction.

Weather data

Since this analysis focuses on Jersey City, weather data from Newark Airport (EWR) is used. The following time series plots display precipitation, wind speed, and temperature for each hour in Jersey City during April 2022. The plots reveal a few days of precipitation, with a noticeable increase in temperature around mid-April.

grid.arrange(
  ggplot(weather.Panel, aes(interval60,Precipitation)) + geom_line() + 
  labs(title="Percipitation", x="Hour", y="Perecipitation") + plotTheme,
  ggplot(weather.Panel, aes(interval60,Wind_Speed)) + geom_line() + 
    labs(title="Wind Speed", x="Hour", y="Wind Speed") + plotTheme,
  ggplot(weather.Panel, aes(interval60,Temperature)) + geom_line() + 
    labs(title="Temperature", x="Hour", y="Temperature") + plotTheme,
  top="Weather Data - ERW airport - Arpil, 2022")

Describe and Explore the Data

The Time Series Plot below illustrate Bike share tripe per hours in Jersey City. The blue line is used to visualize the Friday. In can see the relatively low ride share in early April.

ggplot(dat_census %>%
         group_by(interval60) %>%
         tally())+
  geom_line(aes(x = interval60, y = n))+
  labs(title="Bike share trips per hr. Jersey City, April, 2022",
       x="Date", 
       y="Number of trips")+
          #geom_vline(data = monday, aes(xintercept = monday), color = "red") +
          geom_vline(data = Friday, aes(xintercept = Friday), color = "blue") +

  plotTheme

The following plots display bike share trips in Jersey City, broken down by day of the week and by weekdays versus weekends. The data shows a peak in trip counts on Fridays, with overall higher trip volumes on weekdays compared to weekends. This trend indicates that bike sharing is more commonly used for commuting or weekday activities than for weekend use.

ggplot(dat_census %>% mutate(hour = hour(started_at)))+
     geom_freqpoly(aes(hour, color = dotw), binwidth = 1)+
  labs(title="Bike share trips in Jersey, by day of the week, April, 2022",
       x="Hour", 
       y="Trip Counts")+
     plotTheme

ggplot(dat_census %>% 
         mutate(hour = hour(started_at),
                weekend = ifelse(dotw %in% c("Sun", "Sat"), "Weekend", "Weekday")))+
     geom_freqpoly(aes(hour, color = weekend), binwidth = 1)+
  labs(title="Bike share trips in Jersey - weekend vs weekday, April, 2022",
       x="Hour", 
       y="Trip Counts")+
     plotTheme

The maps below show the hourly bike share trips by station. Weekdays generally have higher bike share trips compared to weekends. Overall, stations near the Hudson River, especially those close to Manhattan, exhibit relatively higher bike share counts, particularly during weekday PM rush hours.

ggplot()+
  geom_sf(data = NJTracts %>%
          st_transform(crs=4326))+
  geom_point(data = dat_census %>% 
            mutate(hour = hour(started_at),
                weekend = ifelse(dotw %in% c("Sun", "Sat"), "Weekend", "Weekday"),
                time_of_day = case_when(hour(interval60) < 7 | hour(interval60) > 19 ~ "Overnight",
                                 hour(interval60) >= 7 & hour(interval60) < 10 ~ "AM Rush",
                                 hour(interval60) >= 10 & hour(interval60) < 15 ~ "Mid-Day",
                                 hour(interval60) >= 15 & hour(interval60) <= 19 ~ "PM Rush"))%>%
              group_by(start_station_id, start_lat, start_lng, weekend, time_of_day) %>%
              tally() ,
            aes(x=start_lng, y = start_lat, color = n), 
            fill = "transparent", alpha = 0.9, size = 0.9)+
  scale_colour_viridis(direction = -1,
  discrete = FALSE, option = "D")+
  ylim(min(dat_census$start_lat), max(dat_census$start_lat))+
  xlim(min(dat_census$start_lng), max(dat_census$start_lng))+
  facet_grid(weekend ~ time_of_day)+
  labs(title="Bike share trips per hr by station. Jersey, April, 2022")+
  mapTheme

Run Model and Predict for test data

This section split data into a training and test set and develop a 3 week training set and a 2 week test set of all the stations. In the following analysis, four different linear regression are estimated on ride.Train. - reg 1 focuses on just time, including hour fixed effects, day of week and weather temperature - reg 2 focuses on space effect with the station name fixed effects. - reg 3 focuses on both time and space fixed effects. - reg 4 adds the lag features.

The time lag variables will add additional nuance about the demand during a given time period - hours before and during that day.

ride.Train <- filter(ride.panel, week >= 15)
ride.Test <- filter(ride.panel, week < 15)

reg1 <- 
  lm(Trip_Count ~  hour(interval60) + dotw + Temperature,  data=ride.Train)

reg2 <- 
  lm(Trip_Count ~  start_station_name + dotw + Temperature,  data=ride.Train)

reg3 <- 
  lm(Trip_Count ~  start_station_name + hour(interval60) + dotw + Temperature + Precipitation, 
     data=ride.Train)

reg4 <- 
  lm(Trip_Count ~  start_station_name +  hour(interval60) + dotw + Temperature + Precipitation +
                   lagHour + lag2Hours +lag3Hours + lag12Hours + lag1day, 
     data=ride.Train)

#reg5 <- 
  #lm(Trip_Count ~  start_station_name + hour(interval60) + dotw + Temperature + Precipitation +
                   #lagHour + lag2Hours +lag3Hours +lag12Hours + lag1day + holiday, 
     #data=ride.Train)
ride.Test.weekNest <- 
  ride.Test %>%
  nest(-week) 

model_pred <- function(dat, fit){
   pred <- predict(fit, newdata = dat)}

Mean Absolute Error (MAE) is calculated on ride.Test for each model. The plots below illustrate the MAE values for the four models. It displays the highest MAE value in the model that only focuses on time, and the lowest MAE value in the model that add lag features. Therefore, the time lag feature lead the model be better prediction.

week_predictions %>%
  dplyr::select(week, Regression, MAE) %>%
  gather(Variable, MAE, -Regression, -week) %>%
  ggplot(aes(week, MAE)) + 
    geom_bar(aes(fill = Regression), position = "dodge", stat="identity") +
    scale_fill_manual(values = palette5) +
    labs(title = "Mean Absolute Errors by model specification and week") +
  plotTheme

The time series plot below shows the predicted and observed bike counts for a 2-week test set. Overall, the models tend to under-predict the observed values. Among all regression models, Model 4, which incorporates all features, demonstrates the highest accuracy. Therefore, the subsequent analysis is based on Model 4.

week_predictions %>% 
    mutate(interval60 = map(data, pull, interval60),
           start_station_id = map(data, pull, start_station_id)) %>%
    dplyr::select(interval60, start_station_id, Observed, Prediction, Regression) %>%
    unnest() %>%
    gather(Variable, Value, -Regression, -interval60, -start_station_id) %>%
    group_by(Regression, Variable, interval60) %>%
    summarize(Value = sum(Value)) %>%
    ggplot(aes(interval60, Value, colour=Variable)) + 
      geom_line(size = 1.1) + 
      facet_wrap(~Regression, ncol=1) +
      labs(title = "Predicted/Observed bike share time series", subtitle = "Jersey; A test set of 2 weeks",  x = "Hour", y= "Station Trips") +
      plotTheme

The map below displays the distribution of MAE values using Model 4 in Jersey City. Higher MAE values are observed near the Hudson River, particularly in areas closer to Manhattan.

week_predictions %>% 
    mutate(interval60 = map(data, pull, interval60),
           start_station_id = map(data, pull, start_station_id), 
           start_lat = map(data, pull, start_lat), 
           start_lng = map(data, pull, start_lng)) %>%
    select(interval60, start_station_id, start_lng, start_lat, Observed, Prediction, Regression) %>%
    unnest() %>%
  filter(Regression == "DTime_Space_FE_timeLags") %>%
  group_by(start_station_id, start_lng, start_lat) %>%
  summarize(MAE = mean(abs(Observed-Prediction), na.rm = TRUE))%>%
ggplot(.)+
  geom_sf(data = NJ_Census, color = "grey", fill = "transparent")+
  geom_point(aes(x = start_lng, y = start_lat, color = MAE, size = MAE), 
             fill = "transparent", alpha = 0.8) +
  scale_colour_viridis(
    name = "Mean Absolute Error", # Combined title for color and size
    direction = -1,
    option = "D",
    discrete = FALSE
  ) +
  scale_size_continuous(
    name = "Mean Absolute Error", # Same title as color to combine legend
    range = c(1, 5) # Adjust size range as needed
  ) +
  guides(
    color = guide_legend() # Use a single legend guide
  ) +
  ylim(min(dat_census$start_lat), max(dat_census$start_lat))+
  xlim(min(dat_census$start_lng), max(dat_census$start_lng))+
  labs(title="Mean Abs Error, Test Set, Model 4")+
  mapTheme

Space-Time Error Evaluation

The following scatterplots show the observed versus predicted values for different time periods of the day on weekdays and weekends. Overall, the predicted values tend to under-predict the observed values. However, the weekend exhibits relatively smaller errors compared to weekdays, as indicated by the red line being closer to the black line.

week_predictions %>% 
    mutate(interval60 = map(data, pull, interval60),
           start_station_id = map(data, pull, start_station_id), 
           start_lat = map(data, pull, start_lat), 
           start_lng = map(data, pull, start_lng),
           dotw = map(data, pull, dotw)) %>%
    select(interval60, start_station_id, start_lng, 
           start_lat, Observed, Prediction, Regression,
           dotw) %>%
    unnest() %>%
  filter(Regression == "DTime_Space_FE_timeLags")%>%
  mutate(weekend = ifelse(dotw %in% c("Sun", "Sat"), "Weekend", "Weekday"),
         time_of_day = case_when(hour(interval60) < 7 | hour(interval60) > 18 ~ "Overnight",
                                 hour(interval60) >= 7 & hour(interval60) < 10 ~ "AM Rush",
                                 hour(interval60) >= 10 & hour(interval60) < 15 ~ "Mid-Day",
                                 hour(interval60) >= 15 & hour(interval60) <= 18 ~ "PM Rush"))%>%
  ggplot()+
  geom_point(aes(x= Observed, y = Prediction))+
    geom_smooth(aes(x= Observed, y= Prediction), method = "lm", se = FALSE, color = "red")+
    geom_abline(slope = 1, intercept = 0)+
  facet_grid(time_of_day~weekend)+
  labs(title="Observed vs Predicted",
       x="Observed trips", 
       y="Predicted trips")+
  plotTheme

The maps below display the distribution of MAE values in Jersey City during different time periods on weekdays and weekends. Overall, areas near the Hudson River exhibit relatively higher MAE values. Additionally, the model performs better during the overnight period, as indicated by lower MAE values.

week_predictions %>% 
    mutate(interval60 = map(data, pull, interval60),
           start_station_id = map(data, pull, start_station_id), 
           start_lat = map(data, pull, start_lat), 
           start_lng = map(data, pull, start_lng),
           dotw = map(data, pull, dotw) ) %>%
    select(interval60, start_station_id, start_lng, 
           start_lat, Observed, Prediction, Regression,
           dotw) %>%
    unnest() %>%
  filter(Regression == "DTime_Space_FE_timeLags")%>%
  mutate(weekend = ifelse(dotw %in% c("Sun", "Sat"), "Weekend", "Weekday"),
         time_of_day = case_when(hour(interval60) < 7 | hour(interval60) > 18 ~ "Overnight",
                                 hour(interval60) >= 7 & hour(interval60) < 10 ~ "AM Rush",
                                 hour(interval60) >= 10 & hour(interval60) < 15 ~ "Mid-Day",
                                 hour(interval60) >= 15 & hour(interval60) <= 18 ~ "PM Rush")) %>%
  group_by(start_station_id, weekend, time_of_day, start_lng, start_lat) %>%
  summarize(MAE = mean(abs(Observed-Prediction), na.rm = TRUE))%>%
  ggplot(.)+
  geom_sf(data = NJ_Census, color = "grey", fill = "transparent")+
   geom_point(aes(x = start_lng, y = start_lat, color = MAE), 
             fill = "transparent", alpha = 0.5, size = 1.5) +
  scale_colour_viridis(direction = -1,
  discrete = FALSE, option = "D") +
  ylim(min(dat_census$start_lat), max(dat_census$start_lat))+
  xlim(min(dat_census$start_lng), max(dat_census$start_lng))+
  facet_grid(weekend~time_of_day)+
  labs(title="Mean Absolute Errors, Test Set")+
  mapTheme

The following scatterplots explore the relationship between errors and socio-economic features. The analysis reveals that areas with lower income, a smaller proportion of residents using public transportation, and a lower percentage of white residents tend to have lower MAE values, indicating that these areas are more accurately predicted by the model.

week_predictions %>% 
    mutate(interval60 = map(data, pull, interval60),
           start_station_id = map(data, pull, start_station_id), 
           start_lat = map(data, pull, start_lat), 
           start_lng = map(data, pull, start_lng),
           dotw = map(data, pull, dotw),
           Percent_Taking_Public_Trans = map(data, pull, Percent_Taking_Public_Trans),
           Med_Inc = map(data, pull, Med_Inc),
           Percent_White = map(data, pull, Percent_White)) %>%
    select(interval60, start_station_id, start_lat, 
           start_lng, Observed, Prediction, Regression,
           dotw, Percent_Taking_Public_Trans, Med_Inc, Percent_White) %>%
    unnest() %>%
  filter(Regression == "DTime_Space_FE_timeLags")%>%
  mutate(weekend = ifelse(dotw %in% c("Sun", "Sat"), "Weekend", "Weekday"),
         time_of_day = case_when(hour(interval60) < 7 | hour(interval60) > 18 ~ "Overnight",
                                 hour(interval60) >= 7 & hour(interval60) < 10 ~ "AM Rush",
                                 hour(interval60) >= 10 & hour(interval60) < 15 ~ "Mid-Day",
                                 hour(interval60) >= 15 & hour(interval60) <= 18 ~ "PM Rush")) %>%
  filter(time_of_day == "AM Rush") %>%
  group_by(start_station_id, Percent_Taking_Public_Trans, Med_Inc, Percent_White) %>%
  summarize(MAE = mean(abs(Observed-Prediction), na.rm = TRUE))%>%
  gather(-start_station_id, -MAE, key = "variable", value = "value")%>%
  ggplot(.)+
  #geom_sf(data = chicagoCensus, color = "grey", fill = "transparent")+
  geom_point(aes(x = value, y = MAE), alpha = 0.4)+
  geom_smooth(aes(x = value, y = MAE), method = "lm", se= FALSE)+
  facet_wrap(~variable, scales = "free")+
  labs(title="Errors as a function of socio-economic variables",
       y="Mean Absolute Error (Trips)")+
  plotTheme

Conclusion

Overall, bike stations near the Hudson River, particularly those close to Manhattan, exhibit higher bike share counts, likely reflecting a high volume of commuters traveling for work, study, or other daily activities. Additionally, these stations tend to have relatively larger Mean Absolute Error (MAE) values, showing a tendency for under-prediction compared to other stations. This suggests a high demand for bikes in areas near the Hudson River. To address bike re-balancing plan, it is essential to ensure that stations anticipated to experience high demand are adequately supplied with bikes. Based on the model analysis, allocating more bikes to stations near the Hudson River is a necessary step to meet this demand effectively.

LS0tCnRpdGxlOiAiSFc1YiAtIEJpa2UgU2hhcmUgUHJlZGljdGlvbiIKZGF0ZTogIjIwMjQtMTEtMTMiCmF1dGhvcjogSmlhdG9uZyBTdQpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBzaW1wbGV4CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHByb2dyZXNzOiBoaWRlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogIHBhcmFtczoKICBpbmNsdWRlX3dhcm5pbmdzOiBmYWxzZSAgIyBBZGQgdGhpcyBsaW5lIHRvIHN1cHByZXNzIHdhcm5pbmdzCi0tLQoKIyBJbnRyb2R1Y3Rpb24KCkJpa2Ugc2hhcmUgc3lzdGVtcyBwcm92aWRlIGFuIGVjby1mcmllbmRseSB0cmFuc3BvcnRhdGlvbiBvcHRpb24sIGJ1dCBvbmUgb2YgdGhlIGJvZyBvcGVyYXRpb25hbCBjaGFsbGVuZ2UgaXMgInJlLWJhbGFuY2luZyIsIHdoaWNoIGVuc3VyaW5nIGJpa2VzIGFyZSBldmVubHkgZGlzdHJpYnV0ZWQgYWNyb3NzIHN0YXRpb25zIHRvIG1lZXQgZGVtYW5kLiBUaGlzIGFuYWx5c2lzIGV4YW1pbmVzIGJpa2UgcHJlZGljdGlvbiBmb3IgdGhlIE5ZIGNpdHkgQmlrZSBpbiBKZXJzZXkgY2l0eSwgd2hpY2ggdXRpbGl6ZSBOWSBjaXR5IEJpa2UgZGF0YSBpbiBBcHJpbCwgMjAyMiwgYWxvbmcgd2l0aCBjZW5zdXMgYW5kIGNsaW1hdGUgaW5mb3JtYXRpb24uCgpCeSBkZXZlbG9waW5nIGEgc3BhY2UtdGltZSBwcmVkaWN0aXZlIG1vZGVsLCB0aGUgc3R1ZHkgaWRlbnRpZmllcyBwYXR0ZXJucyBpbiBiaWtlIGRlbWFuZCBiYXNlZCBvbiBzb2Npby1lY29ub21pYyBmYWN0b3JzLCB3ZWF0aGVyLCBhbmQgY29tbXV0aW5nIHRyZW5kcywgcGFydGljdWxhcmx5IG5lYXIgaGlnaC1kZW1hbmQgYXJlYXMgbGlrZSB0aGUgSHVkc29uIFJpdmVyIGFuZCBNYW5oYXR0YW4uIFRoZXNlIGluc2lnaHRzIGFpbSB0byBpbXByb3ZlIGJpa2UgcmUtYmFsYW5jaW5nIHN0cmF0ZWdpZXMsIGVuc3VyaW5nIGVmZmljaWVudCBvcGVyYXRpb25zIGFuZCBiZXR0ZXIgdXNlciBzYXRpc2ZhY3Rpb24uCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQoKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoc2YpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHRpZ3JpcykKbGlicmFyeSh0aWR5Y2Vuc3VzKQpsaWJyYXJ5KHZpcmlkaXMpCmxpYnJhcnkocmllbSkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkodG1hcCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCgpwbG90VGhlbWUgPC0gdGhlbWUoCiAgcGxvdC50aXRsZSA9ZWxlbWVudF90ZXh0KHNpemU9MTIpLAogIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04KSwKICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICMgU2V0IHRoZSBlbnRpcmUgY2hhcnQgcmVnaW9uIHRvIGJsYW5rCiAgcGFuZWwuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksCiAgcGxvdC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwKICAjcGFuZWwuYm9yZGVyPWVsZW1lbnRfcmVjdChjb2xvdXI9IiNGMEYwRjAiKSwKICAjIEZvcm1hdCB0aGUgZ3JpZAogIHBhbmVsLmdyaWQubWFqb3I9ZWxlbWVudF9saW5lKGNvbG91cj0iI0QwRDBEMCIsc2l6ZT0uMiksCiAgYXhpcy50aWNrcz1lbGVtZW50X2JsYW5rKCkpCgptYXBUaGVtZSA8LSB0aGVtZShwbG90LnRpdGxlID1lbGVtZW50X3RleHQoc2l6ZT0xMiksCiAgICAgICAgICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04KSwKICAgICAgICAgICAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgIGF4aXMudGlja3M9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgcGFuZWwuYm9yZGVyPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvcj1lbGVtZW50X2xpbmUoY29sb3VyID0gJ3RyYW5zcGFyZW50JyksCiAgICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3I9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gInZlcnRpY2FsIiwgCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgICAgICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDEsIDEsIDEsIDEsICdjbScpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMSwgImNtIiksIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDAuMiwgImNtIikKICAgICAgICAgICAgICAgICAgKQoKcGFsZXR0ZTUgPC0gYygiI2VmZjNmZiIsIiNiZGQ3ZTciLCIjNmJhZWQ2IiwiIzMxODJiZCIsIiMwODUxOWMiKQpwYWxldHRlNCA8LSBjKCIjRDJGQkQ0IiwiIzkyQkNBQiIsIiM1MjdEODIiLCIjMTIzRjVBIikKcGFsZXR0ZTIgPC0gYygiIzZiYWVkNiIsIiMwODUxOWMiKQoKCnRpZHljZW5zdXM6OmNlbnN1c19hcGlfa2V5KCJlNzlmMzcwNmI2ZDYxMjQ5OTY4YzZjZTg4Nzk0ZjZmNTU2ZTViZjNkIiwgb3ZlcndyaXRlID0gVFJVRSkKCmRhdCA8LSByZWFkX2NzdigiL1VzZXJzL2ppYXRvbmcvRGVza3RvcC9KQy0yMDIyMDQtY2l0aWJpa2UtdHJpcGRhdGEuY3N2IikgIzIwMjIwNAoKYGBgCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KZGF0XzEgPC0gZGF0ICU+JQogIG11dGF0ZShpbnRlcnZhbDYwID0gZmxvb3JfZGF0ZSh5bWRfaG1zKHN0YXJ0ZWRfYXQpLCB1bml0ID0gImhvdXIiKSwKICAgICAgICAgaW50ZXJ2YWwxNSA9IGZsb29yX2RhdGUoeW1kX2htcyhzdGFydGVkX2F0KSwgdW5pdCA9ICIxNSBtaW5zIiksCiAgICAgICAgIHdlZWsgPSB3ZWVrKGludGVydmFsNjApLAogICAgICAgICBkb3R3ID0gd2RheShpbnRlcnZhbDYwLCBsYWJlbD1UUlVFKSkKCmRhdF8xWzE6MywgYygxLDQ6NyldCgpgYGAKCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQpkYXRfMSAlPiUgZ3JvdXBfYnkod2VlaykgJT4lIAogIHN1bW1hcmlzZSgKICAgIGNvdW50ID0gbigpICAjIENvdW50cyB0aGUgbnVtYmVyIG9mIGVudHJpZXMgcGVyIHdlZWsKICApICU+JSBrYWJsZSgpCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0V9Ck5KX0NlbnN1cyA8LSAKICBnZXRfYWNzKGdlb2dyYXBoeSA9ICJ0cmFjdCIsIAogICAgICAgICAgdmFyaWFibGVzID0gYygiQjAxMDAzXzAwMSIsICJCMTkwMTNfMDAxIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICJCMDIwMDFfMDAyIiwgIkIwODAxM18wMDEiLAogICAgICAgICAgICAgICAgICAgICAgICAiQjA4MDEyXzAwMSIsICJCMDgzMDFfMDAxIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICJCMDgzMDFfMDEwIiwgIkIwMTAwMl8wMDEiKSwgCiAgICAgICAgICB5ZWFyID0gMjAyMiwgCiAgICAgICAgICBzdGF0ZSA9ICJOSiIsIAogICAgICAgICAgZ2VvbWV0cnkgPSBUUlVFLCAKICAgICAgICAgIGNvdW50eSA9ICJIdWRzb24iLAogICAgICAgICAgb3V0cHV0ID0gIndpZGUiKSAlPiUKICByZW5hbWUoVG90YWxfUG9wID0gIEIwMTAwM18wMDFFLAogICAgICAgICBNZWRfSW5jID0gQjE5MDEzXzAwMUUsCiAgICAgICAgIE1lZF9BZ2UgPSBCMDEwMDJfMDAxRSwKICAgICAgICAgV2hpdGVfUG9wID0gQjAyMDAxXzAwMkUsCiAgICAgICAgIFRyYXZlbF9UaW1lID0gQjA4MDEzXzAwMUUsCiAgICAgICAgIE51bV9Db21tdXRlcnMgPSBCMDgwMTJfMDAxRSwKICAgICAgICAgTWVhbnNfb2ZfVHJhbnNwb3J0ID0gQjA4MzAxXzAwMUUsCiAgICAgICAgIFRvdGFsX1B1YmxpY19UcmFucyA9IEIwODMwMV8wMTBFKSAlPiUKICBzZWxlY3QoVG90YWxfUG9wLCBNZWRfSW5jLCBXaGl0ZV9Qb3AsIFRyYXZlbF9UaW1lLAogICAgICAgICBNZWFuc19vZl9UcmFuc3BvcnQsIFRvdGFsX1B1YmxpY19UcmFucywKICAgICAgICAgTWVkX0FnZSwKICAgICAgICAgR0VPSUQsIGdlb21ldHJ5KSAlPiUKICBtdXRhdGUoUGVyY2VudF9XaGl0ZSA9IFdoaXRlX1BvcCAvIFRvdGFsX1BvcCwKICAgICAgICAgTWVhbl9Db21tdXRlX1RpbWUgPSBUcmF2ZWxfVGltZSAvIFRvdGFsX1B1YmxpY19UcmFucywKICAgICAgICAgUGVyY2VudF9UYWtpbmdfUHVibGljX1RyYW5zID0gVG90YWxfUHVibGljX1RyYW5zIC8gTWVhbnNfb2ZfVHJhbnNwb3J0KSAlPiUgCiAgc3RfdHJhbnNmb3JtKGNycyA9IDQzMjYpCgoKTkpUcmFjdHMgPC0gCiAgTkpfQ2Vuc3VzICU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBkaXN0aW5jdChHRU9JRCwgLmtlZXBfYWxsID0gVFJVRSkgJT4lCiAgc2VsZWN0KEdFT0lELCBnZW9tZXRyeSkgJT4lIAogIHN0X3NmCgoKZGF0X2NlbnN1cyA8LSBzdF9qb2luKGRhdF8xICU+JSAKICAgICAgICAgIGZpbHRlcihpcy5uYShzdGFydF9sbmcpID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgIGlzLm5hKHN0YXJ0X2xhdCkgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgaXMubmEoZW5kX2xhdCkgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgaXMubmEoZW5kX2xuZykgPT0gRkFMU0UpICU+JQogICAgICAgICAgc3RfYXNfc2YoLiwgY29vcmRzID0gYygic3RhcnRfbG5nIiwgInN0YXJ0X2xhdCIpLCBjcnMgPSA0MzI2KSwKICAgICAgICBOSlRyYWN0cyAlPiUKICAgICAgICAgIHN0X3RyYW5zZm9ybShjcnM9NDMyNiksCiAgICAgICAgam9pbj1zdF9pbnRlcnNlY3RzLAogICAgICAgICAgICAgIGxlZnQgPSBUUlVFKSAlPiUKICByZW5hbWUoT3JpZ2luLlRyYWN0ID0gR0VPSUQpICU+JQogIG11dGF0ZShzdGFydF9sbmcgPSB1bmxpc3QobWFwKGdlb21ldHJ5LCAxKSksCiAgICAgICAgIHN0YXJ0X2xhdCA9IHVubGlzdChtYXAoZ2VvbWV0cnksIDIpKSklPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgc2VsZWN0KC1nZW9tZXRyeSklPiUKICBzdF9hc19zZiguLCBjb29yZHMgPSBjKCJlbmRfbG5nIiwgImVuZF9sYXQiKSwgY3JzID0gNDMyNikgJT4lCiAgc3Rfam9pbiguLCBOSlRyYWN0cyAlPiUKICAgICAgICAgICAgc3RfdHJhbnNmb3JtKGNycz00MzI2KSwKICAgICAgICAgIGpvaW49c3RfaW50ZXJzZWN0cywKICAgICAgICAgIGxlZnQgPSBUUlVFKSAlPiUKICByZW5hbWUoRGVzdGluYXRpb24uVHJhY3QgPSBHRU9JRCkgICU+JQogIG11dGF0ZShlbmRfbG5nID0gdW5saXN0KG1hcChnZW9tZXRyeSwgMSkpLAogICAgICAgICBlbmRfbGF0ID0gdW5saXN0KG1hcChnZW9tZXRyeSwgMikpKSU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBzZWxlY3QoLWdlb21ldHJ5KQpgYGAKCiMgV2VhdGhlciBkYXRhCgpTaW5jZSB0aGlzIGFuYWx5c2lzIGZvY3VzZXMgb24gSmVyc2V5IENpdHksIHdlYXRoZXIgZGF0YSBmcm9tIE5ld2FyayBBaXJwb3J0IChFV1IpIGlzIHVzZWQuIFRoZSBmb2xsb3dpbmcgdGltZSBzZXJpZXMgcGxvdHMgZGlzcGxheSBwcmVjaXBpdGF0aW9uLCB3aW5kIHNwZWVkLCBhbmQgdGVtcGVyYXR1cmUgZm9yIGVhY2ggaG91ciBpbiBKZXJzZXkgQ2l0eSBkdXJpbmcgQXByaWwgMjAyMi4gVGhlIHBsb3RzIHJldmVhbCBhIGZldyBkYXlzIG9mIHByZWNpcGl0YXRpb24sIHdpdGggYSBub3RpY2VhYmxlIGluY3JlYXNlIGluIHRlbXBlcmF0dXJlIGFyb3VuZCBtaWQtQXByaWwuCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0Kd2VhdGhlci5QYW5lbCA8LSAKICByaWVtX21lYXN1cmVzKHN0YXRpb24gPSAiRVdSIiwgZGF0ZV9zdGFydCA9ICIyMDIyLTA0LTAxIiwgZGF0ZV9lbmQgPSAiMjAyMi0wNC0zMCIpICU+JQogIGRwbHlyOjpzZWxlY3QodmFsaWQsIHRtcGYsIHAwMWksIHNrbnQpJT4lCiAgcmVwbGFjZShpcy5uYSguKSwgMCkgJT4lCiAgICBtdXRhdGUoaW50ZXJ2YWw2MCA9IHltZF9oKHN1YnN0cih2YWxpZCwxLDEzKSkpICU+JQogICAgbXV0YXRlKHdlZWsgPSB3ZWVrKGludGVydmFsNjApLAogICAgICAgICAgIGRvdHcgPSB3ZGF5KGludGVydmFsNjAsIGxhYmVsPVRSVUUpKSAlPiUKICAgIGdyb3VwX2J5KGludGVydmFsNjApICU+JQogICAgc3VtbWFyaXplKFRlbXBlcmF0dXJlID0gbWF4KHRtcGYpLAogICAgICAgICAgICAgIFByZWNpcGl0YXRpb24gPSBzdW0ocDAxaSksCiAgICAgICAgICAgICAgV2luZF9TcGVlZCA9IG1heChza250KSkgJT4lCiAgICBtdXRhdGUoVGVtcGVyYXR1cmUgPSBpZmVsc2UoVGVtcGVyYXR1cmUgPT0gMCwgNDIsIFRlbXBlcmF0dXJlKSkKCmdsaW1wc2Uod2VhdGhlci5QYW5lbCkKCmBgYAoKYGBge3J9CmdyaWQuYXJyYW5nZSgKICBnZ3Bsb3Qod2VhdGhlci5QYW5lbCwgYWVzKGludGVydmFsNjAsUHJlY2lwaXRhdGlvbikpICsgZ2VvbV9saW5lKCkgKyAKICBsYWJzKHRpdGxlPSJQZXJjaXBpdGF0aW9uIiwgeD0iSG91ciIsIHk9IlBlcmVjaXBpdGF0aW9uIikgKyBwbG90VGhlbWUsCiAgZ2dwbG90KHdlYXRoZXIuUGFuZWwsIGFlcyhpbnRlcnZhbDYwLFdpbmRfU3BlZWQpKSArIGdlb21fbGluZSgpICsgCiAgICBsYWJzKHRpdGxlPSJXaW5kIFNwZWVkIiwgeD0iSG91ciIsIHk9IldpbmQgU3BlZWQiKSArIHBsb3RUaGVtZSwKICBnZ3Bsb3Qod2VhdGhlci5QYW5lbCwgYWVzKGludGVydmFsNjAsVGVtcGVyYXR1cmUpKSArIGdlb21fbGluZSgpICsgCiAgICBsYWJzKHRpdGxlPSJUZW1wZXJhdHVyZSIsIHg9IkhvdXIiLCB5PSJUZW1wZXJhdHVyZSIpICsgcGxvdFRoZW1lLAogIHRvcD0iV2VhdGhlciBEYXRhIC0gRVJXIGFpcnBvcnQgLSBBcnBpbCwgMjAyMiIpCmBgYAoKIyBEZXNjcmliZSBhbmQgRXhwbG9yZSB0aGUgRGF0YQoKYGBge3IsIGluY2x1ZGU9RkFMU0V9Cm1vbmRheSA8LSAKICBtdXRhdGUoZGF0X2NlbnN1cywKICAgICAgICAgbW9uZGF5ID0gaWZlbHNlKGRvdHcgPT0gIk1vbiIgJiBob3VyKGludGVydmFsNjApID09IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICBpbnRlcnZhbDYwLCAwKSkgJT4lCiAgZmlsdGVyKG1vbmRheSAhPSAwKQoKRnJpZGF5IDwtIAogIG11dGF0ZShkYXRfY2Vuc3VzLAogICAgICAgICBGcmlkYXkgPSBpZmVsc2UoZG90dyA9PSAiRnJpIiAmIGhvdXIoaW50ZXJ2YWw2MCkgPT0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgIGludGVydmFsNjAsIDApKSAlPiUKICBmaWx0ZXIoRnJpZGF5ICE9IDApCgpgYGAKClRoZSBUaW1lIFNlcmllcyBQbG90IGJlbG93IGlsbHVzdHJhdGUgQmlrZSBzaGFyZSB0cmlwZSBwZXIgaG91cnMgaW4gSmVyc2V5IENpdHkuIFRoZSBibHVlIGxpbmUgaXMgdXNlZCB0byB2aXN1YWxpemUgdGhlIGBGcmlkYXlgLiBJbiBjYW4gc2VlIHRoZSByZWxhdGl2ZWx5IGxvdyByaWRlIHNoYXJlIGluIGVhcmx5IEFwcmlsLgoKYGBge3J9CmdncGxvdChkYXRfY2Vuc3VzICU+JQogICAgICAgICBncm91cF9ieShpbnRlcnZhbDYwKSAlPiUKICAgICAgICAgdGFsbHkoKSkrCiAgZ2VvbV9saW5lKGFlcyh4ID0gaW50ZXJ2YWw2MCwgeSA9IG4pKSsKICBsYWJzKHRpdGxlPSJCaWtlIHNoYXJlIHRyaXBzIHBlciBoci4gSmVyc2V5IENpdHksIEFwcmlsLCAyMDIyIiwKICAgICAgIHg9IkRhdGUiLCAKICAgICAgIHk9Ik51bWJlciBvZiB0cmlwcyIpKwogICAgICAgICAgI2dlb21fdmxpbmUoZGF0YSA9IG1vbmRheSwgYWVzKHhpbnRlcmNlcHQgPSBtb25kYXkpLCBjb2xvciA9ICJyZWQiKSArCiAgICAgICAgICBnZW9tX3ZsaW5lKGRhdGEgPSBGcmlkYXksIGFlcyh4aW50ZXJjZXB0ID0gRnJpZGF5KSwgY29sb3IgPSAiYmx1ZSIpICsKCiAgcGxvdFRoZW1lCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0V9CmRhdF9jZW5zdXMgJT4lCiAgICAgICAgbXV0YXRlKHRpbWVfb2ZfZGF5ID0gY2FzZV93aGVuKGhvdXIoaW50ZXJ2YWw2MCkgPCA3IHwgaG91cihpbnRlcnZhbDYwKSA+IDE4IH4gIk92ZXJuaWdodCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gNyAmIGhvdXIoaW50ZXJ2YWw2MCkgPCAxMCB+ICJBTSBSdXNoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSAxMCAmIGhvdXIoaW50ZXJ2YWw2MCkgPCAxNSB+ICJNaWQtRGF5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSAxNSAmIGhvdXIoaW50ZXJ2YWw2MCkgPD0gMTggfiAiUE0gUnVzaCIpKSU+JQogICAgICAgICBncm91cF9ieShpbnRlcnZhbDYwLCBzdGFydF9zdGF0aW9uX25hbWUsIHRpbWVfb2ZfZGF5KSAlPiUKICAgICAgICAgdGFsbHkoKSU+JQogIGdyb3VwX2J5KHN0YXJ0X3N0YXRpb25fbmFtZSwgdGltZV9vZl9kYXkpJT4lCiAgc3VtbWFyaXplKG1lYW5fdHJpcHMgPSBtZWFuKG4pKSU+JQogIGdncGxvdCgpKwogIGdlb21faGlzdG9ncmFtKGFlcyhtZWFuX3RyaXBzKSwgYmlud2lkdGggPSAxKSsKICBsYWJzKHRpdGxlPSJNZWFuIE51bWJlciBvZiBIb3VybHkgVHJpcHMgUGVyIFN0YXRpb24uIEplcnNleSwgTWF5LCAyMDE4IiwKICAgICAgIHg9Ik51bWJlciBvZiB0cmlwcyIsIAogICAgICAgeT0iRnJlcXVlbmN5IikrCiAgZmFjZXRfd3JhcCh+dGltZV9vZl9kYXkpKwogIHBsb3RUaGVtZQpgYGAKClRoZSBmb2xsb3dpbmcgcGxvdHMgZGlzcGxheSBiaWtlIHNoYXJlIHRyaXBzIGluIEplcnNleSBDaXR5LCBicm9rZW4gZG93biBieSBkYXkgb2YgdGhlIHdlZWsgYW5kIGJ5IHdlZWtkYXlzIHZlcnN1cyB3ZWVrZW5kcy4gVGhlIGRhdGEgc2hvd3MgYSBwZWFrIGluIHRyaXAgY291bnRzIG9uIEZyaWRheXMsIHdpdGggb3ZlcmFsbCBoaWdoZXIgdHJpcCB2b2x1bWVzIG9uIHdlZWtkYXlzIGNvbXBhcmVkIHRvIHdlZWtlbmRzLiBUaGlzIHRyZW5kIGluZGljYXRlcyB0aGF0IGJpa2Ugc2hhcmluZyBpcyBtb3JlIGNvbW1vbmx5IHVzZWQgZm9yIGNvbW11dGluZyBvciB3ZWVrZGF5IGFjdGl2aXRpZXMgdGhhbiBmb3Igd2Vla2VuZCB1c2UuCgpgYGB7cn0KZ2dwbG90KGRhdF9jZW5zdXMgJT4lIG11dGF0ZShob3VyID0gaG91cihzdGFydGVkX2F0KSkpKwogICAgIGdlb21fZnJlcXBvbHkoYWVzKGhvdXIsIGNvbG9yID0gZG90dyksIGJpbndpZHRoID0gMSkrCiAgbGFicyh0aXRsZT0iQmlrZSBzaGFyZSB0cmlwcyBpbiBKZXJzZXksIGJ5IGRheSBvZiB0aGUgd2VlaywgQXByaWwsIDIwMjIiLAogICAgICAgeD0iSG91ciIsIAogICAgICAgeT0iVHJpcCBDb3VudHMiKSsKICAgICBwbG90VGhlbWUKCmBgYAoKYGBge3J9CmdncGxvdChkYXRfY2Vuc3VzICU+JSAKICAgICAgICAgbXV0YXRlKGhvdXIgPSBob3VyKHN0YXJ0ZWRfYXQpLAogICAgICAgICAgICAgICAgd2Vla2VuZCA9IGlmZWxzZShkb3R3ICVpbiUgYygiU3VuIiwgIlNhdCIpLCAiV2Vla2VuZCIsICJXZWVrZGF5IikpKSsKICAgICBnZW9tX2ZyZXFwb2x5KGFlcyhob3VyLCBjb2xvciA9IHdlZWtlbmQpLCBiaW53aWR0aCA9IDEpKwogIGxhYnModGl0bGU9IkJpa2Ugc2hhcmUgdHJpcHMgaW4gSmVyc2V5IC0gd2Vla2VuZCB2cyB3ZWVrZGF5LCBBcHJpbCwgMjAyMiIsCiAgICAgICB4PSJIb3VyIiwgCiAgICAgICB5PSJUcmlwIENvdW50cyIpKwogICAgIHBsb3RUaGVtZQoKYGBgCgpUaGUgbWFwcyBiZWxvdyBzaG93IHRoZSBob3VybHkgYmlrZSBzaGFyZSB0cmlwcyBieSBzdGF0aW9uLiBXZWVrZGF5cyBnZW5lcmFsbHkgaGF2ZSBoaWdoZXIgYmlrZSBzaGFyZSB0cmlwcyBjb21wYXJlZCB0byB3ZWVrZW5kcy4gT3ZlcmFsbCwgc3RhdGlvbnMgbmVhciB0aGUgSHVkc29uIFJpdmVyLCBlc3BlY2lhbGx5IHRob3NlIGNsb3NlIHRvIE1hbmhhdHRhbiwgZXhoaWJpdCByZWxhdGl2ZWx5IGhpZ2hlciBiaWtlIHNoYXJlIGNvdW50cywgcGFydGljdWxhcmx5IGR1cmluZyB3ZWVrZGF5IFBNIHJ1c2ggaG91cnMuCgpgYGB7cn0KZ2dwbG90KCkrCiAgZ2VvbV9zZihkYXRhID0gTkpUcmFjdHMgJT4lCiAgICAgICAgICBzdF90cmFuc2Zvcm0oY3JzPTQzMjYpKSsKICBnZW9tX3BvaW50KGRhdGEgPSBkYXRfY2Vuc3VzICU+JSAKICAgICAgICAgICAgbXV0YXRlKGhvdXIgPSBob3VyKHN0YXJ0ZWRfYXQpLAogICAgICAgICAgICAgICAgd2Vla2VuZCA9IGlmZWxzZShkb3R3ICVpbiUgYygiU3VuIiwgIlNhdCIpLCAiV2Vla2VuZCIsICJXZWVrZGF5IiksCiAgICAgICAgICAgICAgICB0aW1lX29mX2RheSA9IGNhc2Vfd2hlbihob3VyKGludGVydmFsNjApIDwgNyB8IGhvdXIoaW50ZXJ2YWw2MCkgPiAxOSB+ICJPdmVybmlnaHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDcgJiBob3VyKGludGVydmFsNjApIDwgMTAgfiAiQU0gUnVzaCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTAgJiBob3VyKGludGVydmFsNjApIDwgMTUgfiAiTWlkLURheSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTUgJiBob3VyKGludGVydmFsNjApIDw9IDE5IH4gIlBNIFJ1c2giKSklPiUKICAgICAgICAgICAgICBncm91cF9ieShzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9sYXQsIHN0YXJ0X2xuZywgd2Vla2VuZCwgdGltZV9vZl9kYXkpICU+JQogICAgICAgICAgICAgIHRhbGx5KCkgLAogICAgICAgICAgICBhZXMoeD1zdGFydF9sbmcsIHkgPSBzdGFydF9sYXQsIGNvbG9yID0gbiksIAogICAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwgYWxwaGEgPSAwLjksIHNpemUgPSAwLjkpKwogIHNjYWxlX2NvbG91cl92aXJpZGlzKGRpcmVjdGlvbiA9IC0xLAogIGRpc2NyZXRlID0gRkFMU0UsIG9wdGlvbiA9ICJEIikrCiAgeWxpbShtaW4oZGF0X2NlbnN1cyRzdGFydF9sYXQpLCBtYXgoZGF0X2NlbnN1cyRzdGFydF9sYXQpKSsKICB4bGltKG1pbihkYXRfY2Vuc3VzJHN0YXJ0X2xuZyksIG1heChkYXRfY2Vuc3VzJHN0YXJ0X2xuZykpKwogIGZhY2V0X2dyaWQod2Vla2VuZCB+IHRpbWVfb2ZfZGF5KSsKICBsYWJzKHRpdGxlPSJCaWtlIHNoYXJlIHRyaXBzIHBlciBociBieSBzdGF0aW9uLiBKZXJzZXksIEFwcmlsLCAyMDIyIikrCiAgbWFwVGhlbWUKCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0V9Cmxlbmd0aCh1bmlxdWUoZGF0X2NlbnN1cyRpbnRlcnZhbDYwKSkgKiBsZW5ndGgodW5pcXVlKGRhdF9jZW5zdXMkc3RhcnRfc3RhdGlvbl9pZCkpCgpgYGAKCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQpzdHVkeS5wYW5lbCA8LSAKICBleHBhbmQuZ3JpZChpbnRlcnZhbDYwPXVuaXF1ZShkYXRfY2Vuc3VzJGludGVydmFsNjApLCAKICAgICAgICAgICAgICBzdGFydF9zdGF0aW9uX2lkID0gdW5pcXVlKGRhdF9jZW5zdXMkc3RhcnRfc3RhdGlvbl9pZCkpICU+JQogIGxlZnRfam9pbiguLCBkYXRfY2Vuc3VzICU+JQogICAgICAgICAgICAgIHNlbGVjdChzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9zdGF0aW9uX25hbWUsIE9yaWdpbi5UcmFjdCwgc3RhcnRfbG5nLCBzdGFydF9sYXQgKSU+JQogICAgICAgICAgICAgIGRpc3RpbmN0KCkgJT4lCiAgICAgICAgICAgICAgZ3JvdXBfYnkoc3RhcnRfc3RhdGlvbl9pZCkgJT4lCiAgICAgICAgICAgICAgc2xpY2UoMSkpCgpucm93KHN0dWR5LnBhbmVsKQpgYGAKCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQpyaWRlLnBhbmVsXzEgPC0gCiAgZGF0X2NlbnN1cyAlPiUKICBtdXRhdGUoVHJpcF9Db3VudGVyID0gMSkgJT4lCiAgcmlnaHRfam9pbihzdHVkeS5wYW5lbCkgJT4lIAogIGdyb3VwX2J5KGludGVydmFsNjAsIHN0YXJ0X3N0YXRpb25faWQsIHN0YXJ0X3N0YXRpb25fbmFtZSwgT3JpZ2luLlRyYWN0LCBzdGFydF9sbmcsIHN0YXJ0X2xhdCkgJT4lCiAgc3VtbWFyaXplKFRyaXBfQ291bnQgPSBzdW0oVHJpcF9Db3VudGVyLCBuYS5ybT1UKSkgJT4lCiAgbGVmdF9qb2luKHdlYXRoZXIuUGFuZWwpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBmaWx0ZXIoaXMubmEoc3RhcnRfc3RhdGlvbl9pZCkgPT0gRkFMU0UpICU+JQogIG11dGF0ZSh3ZWVrID0gd2VlayhpbnRlcnZhbDYwKSwKICAgICAgICAgZG90dyA9IHdkYXkoaW50ZXJ2YWw2MCwgbGFiZWwgPSBUUlVFKSkgJT4lCiAgZmlsdGVyKGlzLm5hKE9yaWdpbi5UcmFjdCkgPT0gRkFMU0UpCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0V9CnJpZGUucGFuZWwgPC0gCiAgbGVmdF9qb2luKHJpZGUucGFuZWxfMSwgTkpfQ2Vuc3VzICU+JQogICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUKICAgICAgICAgICAgICBzZWxlY3QoLWdlb21ldHJ5KSwgYnkgPSBjKCJPcmlnaW4uVHJhY3QiID0gIkdFT0lEIikpCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0V9CnJpZGUucGFuZWwgPC0gCiAgcmlkZS5wYW5lbCAlPiUgCiAgYXJyYW5nZShzdGFydF9zdGF0aW9uX2lkLCBpbnRlcnZhbDYwKSAlPiUgCiAgbXV0YXRlKGxhZ0hvdXIgPSBkcGx5cjo6bGFnKFRyaXBfQ291bnQsMSksCiAgICAgICAgIGxhZzJIb3VycyA9IGRwbHlyOjpsYWcoVHJpcF9Db3VudCwyKSwKICAgICAgICAgbGFnM0hvdXJzID0gZHBseXI6OmxhZyhUcmlwX0NvdW50LDMpLAogICAgICAgICBsYWc0SG91cnMgPSBkcGx5cjo6bGFnKFRyaXBfQ291bnQsNCksCiAgICAgICAgIGxhZzEySG91cnMgPSBkcGx5cjo6bGFnKFRyaXBfQ291bnQsMTIpLAogICAgICAgICBsYWcxZGF5ID0gZHBseXI6OmxhZyhUcmlwX0NvdW50LDI0KSwKICAgICAgICAgaG9saWRheSA9IGlmZWxzZSh5ZGF5KGludGVydmFsNjApID09IDE0OCwxLDApCiAgICAgICAgICkgJT4lCiAgIG11dGF0ZShkYXkgPSB5ZGF5KGludGVydmFsNjApKSAgCgphcy5kYXRhLmZyYW1lKHJpZGUucGFuZWwpICU+JQogICAgZ3JvdXBfYnkoaW50ZXJ2YWw2MCkgJT4lIAogICAgc3VtbWFyaXNlX2F0KHZhcnMoc3RhcnRzX3dpdGgoImxhZyIpLCAiVHJpcF9Db3VudCIpLCBtZWFuLCBuYS5ybSA9IFRSVUUpICU+JQogICAgZ2F0aGVyKFZhcmlhYmxlLCBWYWx1ZSwgLWludGVydmFsNjAsIC1UcmlwX0NvdW50KSAlPiUKICAgIG11dGF0ZShWYXJpYWJsZSA9IGZhY3RvcihWYXJpYWJsZSwgbGV2ZWxzPWMoImxhZ0hvdXIiLCJsYWcySG91cnMiLCJsYWczSG91cnMiLCJsYWc0SG91cnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibGFnMTJIb3VycyIsImxhZzFkYXkiKSkpJT4lCiAgICBncm91cF9ieShWYXJpYWJsZSkgJT4lICAKICAgIHN1bW1hcml6ZShjb3JyZWxhdGlvbiA9IHJvdW5kKGNvcihWYWx1ZSwgVHJpcF9Db3VudCksMikpCgpgYGAKCiMgUnVuIE1vZGVsIGFuZCBQcmVkaWN0IGZvciB0ZXN0IGRhdGEKClRoaXMgc2VjdGlvbiBzcGxpdCBkYXRhIGludG8gYSB0cmFpbmluZyBhbmQgdGVzdCBzZXQgYW5kIGRldmVsb3AgYSAzIHdlZWsgdHJhaW5pbmcgc2V0IGFuZCBhIDIgd2VlayB0ZXN0IHNldCBvZiBhbGwgdGhlIHN0YXRpb25zLiBJbiB0aGUgZm9sbG93aW5nIGFuYWx5c2lzLCBmb3VyIGRpZmZlcmVudCBsaW5lYXIgcmVncmVzc2lvbiBhcmUgZXN0aW1hdGVkIG9uIGByaWRlLlRyYWluYC4gLSBgcmVnIDFgIGZvY3VzZXMgb24ganVzdCB0aW1lLCBpbmNsdWRpbmcgaG91ciBmaXhlZCBlZmZlY3RzLCBkYXkgb2Ygd2VlayBhbmQgd2VhdGhlciB0ZW1wZXJhdHVyZSAtIGByZWcgMmAgZm9jdXNlcyBvbiBzcGFjZSBlZmZlY3Qgd2l0aCB0aGUgc3RhdGlvbiBuYW1lIGZpeGVkIGVmZmVjdHMuIC0gYHJlZyAzYCBmb2N1c2VzIG9uIGJvdGggdGltZSBhbmQgc3BhY2UgZml4ZWQgZWZmZWN0cy4gLSBgcmVnIDRgIGFkZHMgdGhlIGBsYWdgIGZlYXR1cmVzLgoKVGhlIHRpbWUgbGFnIHZhcmlhYmxlcyB3aWxsIGFkZCBhZGRpdGlvbmFsIG51YW5jZSBhYm91dCB0aGUgZGVtYW5kIGR1cmluZyBhIGdpdmVuIHRpbWUgcGVyaW9kIC0gaG91cnMgYmVmb3JlIGFuZCBkdXJpbmcgdGhhdCBkYXkuCgpgYGB7cn0KcmlkZS5UcmFpbiA8LSBmaWx0ZXIocmlkZS5wYW5lbCwgd2VlayA+PSAxNSkKcmlkZS5UZXN0IDwtIGZpbHRlcihyaWRlLnBhbmVsLCB3ZWVrIDwgMTUpCgpyZWcxIDwtIAogIGxtKFRyaXBfQ291bnQgfiAgaG91cihpbnRlcnZhbDYwKSArIGRvdHcgKyBUZW1wZXJhdHVyZSwgIGRhdGE9cmlkZS5UcmFpbikKCnJlZzIgPC0gCiAgbG0oVHJpcF9Db3VudCB+ICBzdGFydF9zdGF0aW9uX25hbWUgKyBkb3R3ICsgVGVtcGVyYXR1cmUsICBkYXRhPXJpZGUuVHJhaW4pCgpyZWczIDwtIAogIGxtKFRyaXBfQ291bnQgfiAgc3RhcnRfc3RhdGlvbl9uYW1lICsgaG91cihpbnRlcnZhbDYwKSArIGRvdHcgKyBUZW1wZXJhdHVyZSArIFByZWNpcGl0YXRpb24sIAogICAgIGRhdGE9cmlkZS5UcmFpbikKCnJlZzQgPC0gCiAgbG0oVHJpcF9Db3VudCB+ICBzdGFydF9zdGF0aW9uX25hbWUgKyAgaG91cihpbnRlcnZhbDYwKSArIGRvdHcgKyBUZW1wZXJhdHVyZSArIFByZWNpcGl0YXRpb24gKwogICAgICAgICAgICAgICAgICAgbGFnSG91ciArIGxhZzJIb3VycyArbGFnM0hvdXJzICsgbGFnMTJIb3VycyArIGxhZzFkYXksIAogICAgIGRhdGE9cmlkZS5UcmFpbikKCiNyZWc1IDwtIAogICNsbShUcmlwX0NvdW50IH4gIHN0YXJ0X3N0YXRpb25fbmFtZSArIGhvdXIoaW50ZXJ2YWw2MCkgKyBkb3R3ICsgVGVtcGVyYXR1cmUgKyBQcmVjaXBpdGF0aW9uICsKICAgICAgICAgICAgICAgICAgICNsYWdIb3VyICsgbGFnMkhvdXJzICtsYWczSG91cnMgK2xhZzEySG91cnMgKyBsYWcxZGF5ICsgaG9saWRheSwgCiAgICAgI2RhdGE9cmlkZS5UcmFpbikKYGBgCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KcmlkZS5UZXN0LndlZWtOZXN0IDwtIAogIHJpZGUuVGVzdCAlPiUKICBuZXN0KC13ZWVrKSAKCm1vZGVsX3ByZWQgPC0gZnVuY3Rpb24oZGF0LCBmaXQpewogICBwcmVkIDwtIHByZWRpY3QoZml0LCBuZXdkYXRhID0gZGF0KX0KCmBgYAoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CndlZWtfcHJlZGljdGlvbnMgPC0gCiAgcmlkZS5UZXN0LndlZWtOZXN0ICU+JSAKICAgICAgICBtdXRhdGUoQVRpbWVfRkUgPSBtYXAoLnggPSBkYXRhLCBmaXQgPSByZWcxLCAuZiA9IG1vZGVsX3ByZWQpLAogICAgICAgICAgIEJTcGFjZV9GRSA9IG1hcCgueCA9IGRhdGEsIGZpdCA9IHJlZzIsIC5mID0gbW9kZWxfcHJlZCksCiAgICAgICAgICAgQ1RpbWVfU3BhY2VfRkUgPSBtYXAoLnggPSBkYXRhLCBmaXQgPSByZWczLCAuZiA9IG1vZGVsX3ByZWQpLAogICAgICAgICAgIERUaW1lX1NwYWNlX0ZFX3RpbWVMYWdzID0gbWFwKC54ID0gZGF0YSwgZml0ID0gcmVnNCwgLmYgPSBtb2RlbF9wcmVkKSwKICAgICAgICAgICAjRVRpbWVfU3BhY2VfRkVfdGltZUxhZ3NfaG9saWRheUxhZ3MgPSBtYXAoLnggPSBkYXRhLCBmaXQgPSByZWc1LCAuZiA9IG1vZGVsX3ByZWQpCiAgICAgICAgICAgKSAlPiUgCiAgICBnYXRoZXIoUmVncmVzc2lvbiwgUHJlZGljdGlvbiwgLWRhdGEsIC13ZWVrKSAlPiUKICAgIG11dGF0ZShPYnNlcnZlZCA9IG1hcChkYXRhLCBwdWxsLCBUcmlwX0NvdW50KSwKICAgICAgICAgICBBYnNvbHV0ZV9FcnJvciA9IG1hcDIoT2JzZXJ2ZWQsIFByZWRpY3Rpb24sICB+IGFicygueCAtIC55KSksCiAgICAgICAgICAgTUFFID0gbWFwX2RibChBYnNvbHV0ZV9FcnJvciwgbWVhbiwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICBzZF9BRSA9IG1hcF9kYmwoQWJzb2x1dGVfRXJyb3IsIHNkLCBuYS5ybSA9IFRSVUUpKQoKd2Vla19wcmVkaWN0aW9ucwpgYGAKCk1lYW4gQWJzb2x1dGUgRXJyb3IgKE1BRSkgaXMgY2FsY3VsYXRlZCBvbiBgcmlkZS5UZXN0YCBmb3IgZWFjaCBtb2RlbC4gVGhlIHBsb3RzIGJlbG93IGlsbHVzdHJhdGUgdGhlIE1BRSB2YWx1ZXMgZm9yIHRoZSBmb3VyIG1vZGVscy4gSXQgZGlzcGxheXMgdGhlIGhpZ2hlc3QgTUFFIHZhbHVlIGluIHRoZSBtb2RlbCB0aGF0IG9ubHkgZm9jdXNlcyBvbiB0aW1lLCBhbmQgdGhlIGxvd2VzdCBNQUUgdmFsdWUgaW4gdGhlIG1vZGVsIHRoYXQgYWRkIGBsYWdgIGZlYXR1cmVzLiBUaGVyZWZvcmUsIHRoZSB0aW1lIGxhZyBmZWF0dXJlIGxlYWQgdGhlIG1vZGVsIGJlIGJldHRlciBwcmVkaWN0aW9uLgoKYGBge3J9CndlZWtfcHJlZGljdGlvbnMgJT4lCiAgZHBseXI6OnNlbGVjdCh3ZWVrLCBSZWdyZXNzaW9uLCBNQUUpICU+JQogIGdhdGhlcihWYXJpYWJsZSwgTUFFLCAtUmVncmVzc2lvbiwgLXdlZWspICU+JQogIGdncGxvdChhZXMod2VlaywgTUFFKSkgKyAKICAgIGdlb21fYmFyKGFlcyhmaWxsID0gUmVncmVzc2lvbiksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdD0iaWRlbnRpdHkiKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlNSkgKwogICAgbGFicyh0aXRsZSA9ICJNZWFuIEFic29sdXRlIEVycm9ycyBieSBtb2RlbCBzcGVjaWZpY2F0aW9uIGFuZCB3ZWVrIikgKwogIHBsb3RUaGVtZQpgYGAKClRoZSB0aW1lIHNlcmllcyBwbG90IGJlbG93IHNob3dzIHRoZSBwcmVkaWN0ZWQgYW5kIG9ic2VydmVkIGJpa2UgY291bnRzIGZvciBhIDItd2VlayB0ZXN0IHNldC4gT3ZlcmFsbCwgdGhlIG1vZGVscyB0ZW5kIHRvIHVuZGVyLXByZWRpY3QgdGhlIG9ic2VydmVkIHZhbHVlcy4gQW1vbmcgYWxsIHJlZ3Jlc3Npb24gbW9kZWxzLCBNb2RlbCA0LCB3aGljaCBpbmNvcnBvcmF0ZXMgYWxsIGZlYXR1cmVzLCBkZW1vbnN0cmF0ZXMgdGhlIGhpZ2hlc3QgYWNjdXJhY3kuIFRoZXJlZm9yZSwgdGhlIHN1YnNlcXVlbnQgYW5hbHlzaXMgaXMgYmFzZWQgb24gTW9kZWwgNC4KCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQp3ZWVrX3ByZWRpY3Rpb25zICU+JSAKICAgIG11dGF0ZShpbnRlcnZhbDYwID0gbWFwKGRhdGEsIHB1bGwsIGludGVydmFsNjApLAogICAgICAgICAgIHN0YXJ0X3N0YXRpb25faWQgPSBtYXAoZGF0YSwgcHVsbCwgc3RhcnRfc3RhdGlvbl9pZCkpICU+JQogICAgZHBseXI6OnNlbGVjdChpbnRlcnZhbDYwLCBzdGFydF9zdGF0aW9uX2lkLCBPYnNlcnZlZCwgUHJlZGljdGlvbiwgUmVncmVzc2lvbikgJT4lCiAgICB1bm5lc3QoKSAlPiUKICAgIGdhdGhlcihWYXJpYWJsZSwgVmFsdWUsIC1SZWdyZXNzaW9uLCAtaW50ZXJ2YWw2MCwgLXN0YXJ0X3N0YXRpb25faWQpICU+JQogICAgZ3JvdXBfYnkoUmVncmVzc2lvbiwgVmFyaWFibGUsIGludGVydmFsNjApICU+JQogICAgc3VtbWFyaXplKFZhbHVlID0gc3VtKFZhbHVlKSkgJT4lCiAgICBnZ3Bsb3QoYWVzKGludGVydmFsNjAsIFZhbHVlLCBjb2xvdXI9VmFyaWFibGUpKSArIAogICAgICBnZW9tX2xpbmUoc2l6ZSA9IDEuMSkgKyAKICAgICAgZmFjZXRfd3JhcCh+UmVncmVzc2lvbiwgbmNvbD0xKSArCiAgICAgIGxhYnModGl0bGUgPSAiUHJlZGljdGVkL09ic2VydmVkIGJpa2Ugc2hhcmUgdGltZSBzZXJpZXMiLCBzdWJ0aXRsZSA9ICJKZXJzZXk7IEEgdGVzdCBzZXQgb2YgMiB3ZWVrcyIsICB4ID0gIkhvdXIiLCB5PSAiU3RhdGlvbiBUcmlwcyIpICsKICAgICAgcGxvdFRoZW1lCmBgYAoKVGhlIG1hcCBiZWxvdyBkaXNwbGF5cyB0aGUgZGlzdHJpYnV0aW9uIG9mIE1BRSB2YWx1ZXMgdXNpbmcgTW9kZWwgNCBpbiBKZXJzZXkgQ2l0eS4gSGlnaGVyIE1BRSB2YWx1ZXMgYXJlIG9ic2VydmVkIG5lYXIgdGhlIEh1ZHNvbiBSaXZlciwgcGFydGljdWxhcmx5IGluIGFyZWFzIGNsb3NlciB0byBNYW5oYXR0YW4uCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0Kd2Vla19wcmVkaWN0aW9ucyAlPiUgCiAgICBtdXRhdGUoaW50ZXJ2YWw2MCA9IG1hcChkYXRhLCBwdWxsLCBpbnRlcnZhbDYwKSwKICAgICAgICAgICBzdGFydF9zdGF0aW9uX2lkID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X3N0YXRpb25faWQpLCAKICAgICAgICAgICBzdGFydF9sYXQgPSBtYXAoZGF0YSwgcHVsbCwgc3RhcnRfbGF0KSwgCiAgICAgICAgICAgc3RhcnRfbG5nID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X2xuZykpICU+JQogICAgc2VsZWN0KGludGVydmFsNjAsIHN0YXJ0X3N0YXRpb25faWQsIHN0YXJ0X2xuZywgc3RhcnRfbGF0LCBPYnNlcnZlZCwgUHJlZGljdGlvbiwgUmVncmVzc2lvbikgJT4lCiAgICB1bm5lc3QoKSAlPiUKICBmaWx0ZXIoUmVncmVzc2lvbiA9PSAiRFRpbWVfU3BhY2VfRkVfdGltZUxhZ3MiKSAlPiUKICBncm91cF9ieShzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9sbmcsIHN0YXJ0X2xhdCkgJT4lCiAgc3VtbWFyaXplKE1BRSA9IG1lYW4oYWJzKE9ic2VydmVkLVByZWRpY3Rpb24pLCBuYS5ybSA9IFRSVUUpKSU+JQpnZ3Bsb3QoLikrCiAgZ2VvbV9zZihkYXRhID0gTkpfQ2Vuc3VzLCBjb2xvciA9ICJncmV5IiwgZmlsbCA9ICJ0cmFuc3BhcmVudCIpKwogIGdlb21fcG9pbnQoYWVzKHggPSBzdGFydF9sbmcsIHkgPSBzdGFydF9sYXQsIGNvbG9yID0gTUFFLCBzaXplID0gTUFFKSwgCiAgICAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwgYWxwaGEgPSAwLjgpICsKICBzY2FsZV9jb2xvdXJfdmlyaWRpcygKICAgIG5hbWUgPSAiTWVhbiBBYnNvbHV0ZSBFcnJvciIsICMgQ29tYmluZWQgdGl0bGUgZm9yIGNvbG9yIGFuZCBzaXplCiAgICBkaXJlY3Rpb24gPSAtMSwKICAgIG9wdGlvbiA9ICJEIiwKICAgIGRpc2NyZXRlID0gRkFMU0UKICApICsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMoCiAgICBuYW1lID0gIk1lYW4gQWJzb2x1dGUgRXJyb3IiLCAjIFNhbWUgdGl0bGUgYXMgY29sb3IgdG8gY29tYmluZSBsZWdlbmQKICAgIHJhbmdlID0gYygxLCA1KSAjIEFkanVzdCBzaXplIHJhbmdlIGFzIG5lZWRlZAogICkgKwogIGd1aWRlcygKICAgIGNvbG9yID0gZ3VpZGVfbGVnZW5kKCkgIyBVc2UgYSBzaW5nbGUgbGVnZW5kIGd1aWRlCiAgKSArCiAgeWxpbShtaW4oZGF0X2NlbnN1cyRzdGFydF9sYXQpLCBtYXgoZGF0X2NlbnN1cyRzdGFydF9sYXQpKSsKICB4bGltKG1pbihkYXRfY2Vuc3VzJHN0YXJ0X2xuZyksIG1heChkYXRfY2Vuc3VzJHN0YXJ0X2xuZykpKwogIGxhYnModGl0bGU9Ik1lYW4gQWJzIEVycm9yLCBUZXN0IFNldCwgTW9kZWwgNCIpKwogIG1hcFRoZW1lCmBgYAoKIyBTcGFjZS1UaW1lIEVycm9yIEV2YWx1YXRpb24KClRoZSBmb2xsb3dpbmcgc2NhdHRlcnBsb3RzIHNob3cgdGhlIG9ic2VydmVkIHZlcnN1cyBwcmVkaWN0ZWQgdmFsdWVzIGZvciBkaWZmZXJlbnQgdGltZSBwZXJpb2RzIG9mIHRoZSBkYXkgb24gd2Vla2RheXMgYW5kIHdlZWtlbmRzLiBPdmVyYWxsLCB0aGUgcHJlZGljdGVkIHZhbHVlcyB0ZW5kIHRvIHVuZGVyLXByZWRpY3QgdGhlIG9ic2VydmVkIHZhbHVlcy4gSG93ZXZlciwgdGhlIHdlZWtlbmQgZXhoaWJpdHMgcmVsYXRpdmVseSBzbWFsbGVyIGVycm9ycyBjb21wYXJlZCB0byB3ZWVrZGF5cywgYXMgaW5kaWNhdGVkIGJ5IHRoZSByZWQgbGluZSBiZWluZyBjbG9zZXIgdG8gdGhlIGJsYWNrIGxpbmUuCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KCndlZWtfcHJlZGljdGlvbnMgJT4lIAogICAgbXV0YXRlKGludGVydmFsNjAgPSBtYXAoZGF0YSwgcHVsbCwgaW50ZXJ2YWw2MCksCiAgICAgICAgICAgc3RhcnRfc3RhdGlvbl9pZCA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9zdGF0aW9uX2lkKSwgCiAgICAgICAgICAgc3RhcnRfbGF0ID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X2xhdCksIAogICAgICAgICAgIHN0YXJ0X2xuZyA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9sbmcpLAogICAgICAgICAgIGRvdHcgPSBtYXAoZGF0YSwgcHVsbCwgZG90dykpICU+JQogICAgc2VsZWN0KGludGVydmFsNjAsIHN0YXJ0X3N0YXRpb25faWQsIHN0YXJ0X2xuZywgCiAgICAgICAgICAgc3RhcnRfbGF0LCBPYnNlcnZlZCwgUHJlZGljdGlvbiwgUmVncmVzc2lvbiwKICAgICAgICAgICBkb3R3KSAlPiUKICAgIHVubmVzdCgpICU+JQogIGZpbHRlcihSZWdyZXNzaW9uID09ICJEVGltZV9TcGFjZV9GRV90aW1lTGFncyIpJT4lCiAgbXV0YXRlKHdlZWtlbmQgPSBpZmVsc2UoZG90dyAlaW4lIGMoIlN1biIsICJTYXQiKSwgIldlZWtlbmQiLCAiV2Vla2RheSIpLAogICAgICAgICB0aW1lX29mX2RheSA9IGNhc2Vfd2hlbihob3VyKGludGVydmFsNjApIDwgNyB8IGhvdXIoaW50ZXJ2YWw2MCkgPiAxOCB+ICJPdmVybmlnaHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDcgJiBob3VyKGludGVydmFsNjApIDwgMTAgfiAiQU0gUnVzaCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTAgJiBob3VyKGludGVydmFsNjApIDwgMTUgfiAiTWlkLURheSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTUgJiBob3VyKGludGVydmFsNjApIDw9IDE4IH4gIlBNIFJ1c2giKSklPiUKICBnZ3Bsb3QoKSsKICBnZW9tX3BvaW50KGFlcyh4PSBPYnNlcnZlZCwgeSA9IFByZWRpY3Rpb24pKSsKICAgIGdlb21fc21vb3RoKGFlcyh4PSBPYnNlcnZlZCwgeT0gUHJlZGljdGlvbiksIG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZCIpKwogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSsKICBmYWNldF9ncmlkKHRpbWVfb2ZfZGF5fndlZWtlbmQpKwogIGxhYnModGl0bGU9Ik9ic2VydmVkIHZzIFByZWRpY3RlZCIsCiAgICAgICB4PSJPYnNlcnZlZCB0cmlwcyIsIAogICAgICAgeT0iUHJlZGljdGVkIHRyaXBzIikrCiAgcGxvdFRoZW1lCmBgYAoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CndlZWtfcHJlZGljdGlvbnMgJT4lIAogICAgbXV0YXRlKGludGVydmFsNjAgPSBtYXAoZGF0YSwgcHVsbCwgaW50ZXJ2YWw2MCksCiAgICAgICAgICAgc3RhcnRfc3RhdGlvbl9pZCA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9zdGF0aW9uX2lkKSwgCiAgICAgICAgICAgc3RhcnRfbGF0ID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X2xhdCksIAogICAgICAgICAgIHN0YXJ0X2xuZyA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9sbmcpLAogICAgICAgICAgIGRvdHcgPSBtYXAoZGF0YSwgcHVsbCwgZG90dykgKSAlPiUKICAgIHNlbGVjdChpbnRlcnZhbDYwLCBzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9sbmcsIAogICAgICAgICAgIHN0YXJ0X2xhdCwgT2JzZXJ2ZWQsIFByZWRpY3Rpb24sIFJlZ3Jlc3Npb24sCiAgICAgICAgICAgZG90dykgJT4lCiAgICB1bm5lc3QoKSAlPiUKICBmaWx0ZXIoUmVncmVzc2lvbiA9PSAiRFRpbWVfU3BhY2VfRkVfdGltZUxhZ3MiKSU+JQogIG11dGF0ZSh3ZWVrZW5kID0gaWZlbHNlKGRvdHcgJWluJSBjKCJTdW4iLCAiU2F0IiksICJXZWVrZW5kIiwgIldlZWtkYXkiKSwKICAgICAgICAgdGltZV9vZl9kYXkgPSBjYXNlX3doZW4oaG91cihpbnRlcnZhbDYwKSA8IDcgfCBob3VyKGludGVydmFsNjApID4gMTggfiAiT3Zlcm5pZ2h0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSA3ICYgaG91cihpbnRlcnZhbDYwKSA8IDEwIH4gIkFNIFJ1c2giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDEwICYgaG91cihpbnRlcnZhbDYwKSA8IDE1IH4gIk1pZC1EYXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDE1ICYgaG91cihpbnRlcnZhbDYwKSA8PSAxOCB+ICJQTSBSdXNoIikpICU+JQogIGdyb3VwX2J5KHN0YXJ0X3N0YXRpb25faWQsIHdlZWtlbmQsIHRpbWVfb2ZfZGF5LCBzdGFydF9sbmcsIHN0YXJ0X2xhdCkgJT4lCiAgc3VtbWFyaXplKE1BRSA9IG1lYW4oYWJzKE9ic2VydmVkLVByZWRpY3Rpb24pLCBuYS5ybSA9IFRSVUUpKSU+JQogIGdncGxvdCguKSsKICBnZW9tX3NmKGRhdGEgPSBOSl9DZW5zdXMsIGNvbG9yID0gImdyZXkiLCBmaWxsID0gInRyYW5zcGFyZW50IikrCiAgIGdlb21fcG9pbnQoYWVzKHggPSBzdGFydF9sbmcsIHkgPSBzdGFydF9sYXQsIGNvbG9yID0gTUFFLCBzaXplID0gTUFFKSwgCiAgICAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwgYWxwaGEgPSAwLjYpICsKICBzY2FsZV9jb2xvdXJfdmlyaWRpcygKICAgIG5hbWUgPSAiTWVhbiBBYnNvbHV0ZSBFcnJvciIsICMgQ29tYmluZWQgdGl0bGUgZm9yIGNvbG9yIGFuZCBzaXplCiAgICBkaXJlY3Rpb24gPSAtMSwKICAgIG9wdGlvbiA9ICJEIiwKICAgIGRpc2NyZXRlID0gRkFMU0UKICApICsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMoCiAgICBuYW1lID0gIk1lYW4gQWJzb2x1dGUgRXJyb3IiLCAjIFNhbWUgdGl0bGUgYXMgY29sb3IgdG8gY29tYmluZSBsZWdlbmQKICAgIHJhbmdlID0gYygxLCA1KSAjIEFkanVzdCBzaXplIHJhbmdlIGFzIG5lZWRlZAogICkgKwogIGd1aWRlcygKICAgIGNvbG9yID0gZ3VpZGVfbGVnZW5kKCkgIyBVc2UgYSBzaW5nbGUgbGVnZW5kIGd1aWRlCiAgKSArCiAgeWxpbShtaW4oZGF0X2NlbnN1cyRzdGFydF9sYXQpLCBtYXgoZGF0X2NlbnN1cyRzdGFydF9sYXQpKSsKICB4bGltKG1pbihkYXRfY2Vuc3VzJHN0YXJ0X2xuZyksIG1heChkYXRfY2Vuc3VzJHN0YXJ0X2xuZykpKwogIGZhY2V0X2dyaWQod2Vla2VuZH50aW1lX29mX2RheSkrCiAgbGFicyh0aXRsZT0iTWVhbiBBYnNvbHV0ZSBFcnJvcnMsIFRlc3QgU2V0IikrCiAgbWFwVGhlbWUKYGBgCgpUaGUgbWFwcyBiZWxvdyBkaXNwbGF5IHRoZSBkaXN0cmlidXRpb24gb2YgTUFFIHZhbHVlcyBpbiBKZXJzZXkgQ2l0eSBkdXJpbmcgZGlmZmVyZW50IHRpbWUgcGVyaW9kcyBvbiB3ZWVrZGF5cyBhbmQgd2Vla2VuZHMuIE92ZXJhbGwsIGFyZWFzIG5lYXIgdGhlIEh1ZHNvbiBSaXZlciBleGhpYml0IHJlbGF0aXZlbHkgaGlnaGVyIE1BRSB2YWx1ZXMuIEFkZGl0aW9uYWxseSwgdGhlIG1vZGVsIHBlcmZvcm1zIGJldHRlciBkdXJpbmcgdGhlIG92ZXJuaWdodCBwZXJpb2QsIGFzIGluZGljYXRlZCBieSBsb3dlciBNQUUgdmFsdWVzLgoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CndlZWtfcHJlZGljdGlvbnMgJT4lIAogICAgbXV0YXRlKGludGVydmFsNjAgPSBtYXAoZGF0YSwgcHVsbCwgaW50ZXJ2YWw2MCksCiAgICAgICAgICAgc3RhcnRfc3RhdGlvbl9pZCA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9zdGF0aW9uX2lkKSwgCiAgICAgICAgICAgc3RhcnRfbGF0ID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X2xhdCksIAogICAgICAgICAgIHN0YXJ0X2xuZyA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9sbmcpLAogICAgICAgICAgIGRvdHcgPSBtYXAoZGF0YSwgcHVsbCwgZG90dykgKSAlPiUKICAgIHNlbGVjdChpbnRlcnZhbDYwLCBzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9sbmcsIAogICAgICAgICAgIHN0YXJ0X2xhdCwgT2JzZXJ2ZWQsIFByZWRpY3Rpb24sIFJlZ3Jlc3Npb24sCiAgICAgICAgICAgZG90dykgJT4lCiAgICB1bm5lc3QoKSAlPiUKICBmaWx0ZXIoUmVncmVzc2lvbiA9PSAiRFRpbWVfU3BhY2VfRkVfdGltZUxhZ3MiKSU+JQogIG11dGF0ZSh3ZWVrZW5kID0gaWZlbHNlKGRvdHcgJWluJSBjKCJTdW4iLCAiU2F0IiksICJXZWVrZW5kIiwgIldlZWtkYXkiKSwKICAgICAgICAgdGltZV9vZl9kYXkgPSBjYXNlX3doZW4oaG91cihpbnRlcnZhbDYwKSA8IDcgfCBob3VyKGludGVydmFsNjApID4gMTggfiAiT3Zlcm5pZ2h0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSA3ICYgaG91cihpbnRlcnZhbDYwKSA8IDEwIH4gIkFNIFJ1c2giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDEwICYgaG91cihpbnRlcnZhbDYwKSA8IDE1IH4gIk1pZC1EYXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDE1ICYgaG91cihpbnRlcnZhbDYwKSA8PSAxOCB+ICJQTSBSdXNoIikpICU+JQogIGdyb3VwX2J5KHN0YXJ0X3N0YXRpb25faWQsIHdlZWtlbmQsIHRpbWVfb2ZfZGF5LCBzdGFydF9sbmcsIHN0YXJ0X2xhdCkgJT4lCiAgc3VtbWFyaXplKE1BRSA9IG1lYW4oYWJzKE9ic2VydmVkLVByZWRpY3Rpb24pLCBuYS5ybSA9IFRSVUUpKSU+JQogIGdncGxvdCguKSsKICBnZW9tX3NmKGRhdGEgPSBOSl9DZW5zdXMsIGNvbG9yID0gImdyZXkiLCBmaWxsID0gInRyYW5zcGFyZW50IikrCiAgIGdlb21fcG9pbnQoYWVzKHggPSBzdGFydF9sbmcsIHkgPSBzdGFydF9sYXQsIGNvbG9yID0gTUFFKSwgCiAgICAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwgYWxwaGEgPSAwLjUsIHNpemUgPSAxLjUpICsKICBzY2FsZV9jb2xvdXJfdmlyaWRpcyhkaXJlY3Rpb24gPSAtMSwKICBkaXNjcmV0ZSA9IEZBTFNFLCBvcHRpb24gPSAiRCIpICsKICB5bGltKG1pbihkYXRfY2Vuc3VzJHN0YXJ0X2xhdCksIG1heChkYXRfY2Vuc3VzJHN0YXJ0X2xhdCkpKwogIHhsaW0obWluKGRhdF9jZW5zdXMkc3RhcnRfbG5nKSwgbWF4KGRhdF9jZW5zdXMkc3RhcnRfbG5nKSkrCiAgZmFjZXRfZ3JpZCh3ZWVrZW5kfnRpbWVfb2ZfZGF5KSsKICBsYWJzKHRpdGxlPSJNZWFuIEFic29sdXRlIEVycm9ycywgVGVzdCBTZXQiKSsKICBtYXBUaGVtZQpgYGAKClRoZSBmb2xsb3dpbmcgc2NhdHRlcnBsb3RzIGV4cGxvcmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGVycm9ycyBhbmQgc29jaW8tZWNvbm9taWMgZmVhdHVyZXMuIFRoZSBhbmFseXNpcyByZXZlYWxzIHRoYXQgYXJlYXMgd2l0aCBsb3dlciBpbmNvbWUsIGEgc21hbGxlciBwcm9wb3J0aW9uIG9mIHJlc2lkZW50cyB1c2luZyBwdWJsaWMgdHJhbnNwb3J0YXRpb24sIGFuZCBhIGxvd2VyIHBlcmNlbnRhZ2Ugb2Ygd2hpdGUgcmVzaWRlbnRzIHRlbmQgdG8gaGF2ZSBsb3dlciBNQUUgdmFsdWVzLCBpbmRpY2F0aW5nIHRoYXQgdGhlc2UgYXJlYXMgYXJlIG1vcmUgYWNjdXJhdGVseSBwcmVkaWN0ZWQgYnkgdGhlIG1vZGVsLgoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CndlZWtfcHJlZGljdGlvbnMgJT4lIAogICAgbXV0YXRlKGludGVydmFsNjAgPSBtYXAoZGF0YSwgcHVsbCwgaW50ZXJ2YWw2MCksCiAgICAgICAgICAgc3RhcnRfc3RhdGlvbl9pZCA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9zdGF0aW9uX2lkKSwgCiAgICAgICAgICAgc3RhcnRfbGF0ID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X2xhdCksIAogICAgICAgICAgIHN0YXJ0X2xuZyA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9sbmcpLAogICAgICAgICAgIGRvdHcgPSBtYXAoZGF0YSwgcHVsbCwgZG90dyksCiAgICAgICAgICAgUGVyY2VudF9UYWtpbmdfUHVibGljX1RyYW5zID0gbWFwKGRhdGEsIHB1bGwsIFBlcmNlbnRfVGFraW5nX1B1YmxpY19UcmFucyksCiAgICAgICAgICAgTWVkX0luYyA9IG1hcChkYXRhLCBwdWxsLCBNZWRfSW5jKSwKICAgICAgICAgICBQZXJjZW50X1doaXRlID0gbWFwKGRhdGEsIHB1bGwsIFBlcmNlbnRfV2hpdGUpKSAlPiUKICAgIHNlbGVjdChpbnRlcnZhbDYwLCBzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9sYXQsIAogICAgICAgICAgIHN0YXJ0X2xuZywgT2JzZXJ2ZWQsIFByZWRpY3Rpb24sIFJlZ3Jlc3Npb24sCiAgICAgICAgICAgZG90dywgUGVyY2VudF9UYWtpbmdfUHVibGljX1RyYW5zLCBNZWRfSW5jLCBQZXJjZW50X1doaXRlKSAlPiUKICAgIHVubmVzdCgpICU+JQogIGZpbHRlcihSZWdyZXNzaW9uID09ICJEVGltZV9TcGFjZV9GRV90aW1lTGFncyIpJT4lCiAgbXV0YXRlKHdlZWtlbmQgPSBpZmVsc2UoZG90dyAlaW4lIGMoIlN1biIsICJTYXQiKSwgIldlZWtlbmQiLCAiV2Vla2RheSIpLAogICAgICAgICB0aW1lX29mX2RheSA9IGNhc2Vfd2hlbihob3VyKGludGVydmFsNjApIDwgNyB8IGhvdXIoaW50ZXJ2YWw2MCkgPiAxOCB+ICJPdmVybmlnaHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDcgJiBob3VyKGludGVydmFsNjApIDwgMTAgfiAiQU0gUnVzaCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTAgJiBob3VyKGludGVydmFsNjApIDwgMTUgfiAiTWlkLURheSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTUgJiBob3VyKGludGVydmFsNjApIDw9IDE4IH4gIlBNIFJ1c2giKSkgJT4lCiAgZmlsdGVyKHRpbWVfb2ZfZGF5ID09ICJBTSBSdXNoIikgJT4lCiAgZ3JvdXBfYnkoc3RhcnRfc3RhdGlvbl9pZCwgUGVyY2VudF9UYWtpbmdfUHVibGljX1RyYW5zLCBNZWRfSW5jLCBQZXJjZW50X1doaXRlKSAlPiUKICBzdW1tYXJpemUoTUFFID0gbWVhbihhYnMoT2JzZXJ2ZWQtUHJlZGljdGlvbiksIG5hLnJtID0gVFJVRSkpJT4lCiAgZ2F0aGVyKC1zdGFydF9zdGF0aW9uX2lkLCAtTUFFLCBrZXkgPSAidmFyaWFibGUiLCB2YWx1ZSA9ICJ2YWx1ZSIpJT4lCiAgZ2dwbG90KC4pKwogICNnZW9tX3NmKGRhdGEgPSBjaGljYWdvQ2Vuc3VzLCBjb2xvciA9ICJncmV5IiwgZmlsbCA9ICJ0cmFuc3BhcmVudCIpKwogIGdlb21fcG9pbnQoYWVzKHggPSB2YWx1ZSwgeSA9IE1BRSksIGFscGhhID0gMC40KSsKICBnZW9tX3Ntb290aChhZXMoeCA9IHZhbHVlLCB5ID0gTUFFKSwgbWV0aG9kID0gImxtIiwgc2U9IEZBTFNFKSsKICBmYWNldF93cmFwKH52YXJpYWJsZSwgc2NhbGVzID0gImZyZWUiKSsKICBsYWJzKHRpdGxlPSJFcnJvcnMgYXMgYSBmdW5jdGlvbiBvZiBzb2Npby1lY29ub21pYyB2YXJpYWJsZXMiLAogICAgICAgeT0iTWVhbiBBYnNvbHV0ZSBFcnJvciAoVHJpcHMpIikrCiAgcGxvdFRoZW1lCmBgYAoKIyBDb25jbHVzaW9uCgpPdmVyYWxsLCBiaWtlIHN0YXRpb25zIG5lYXIgdGhlIEh1ZHNvbiBSaXZlciwgcGFydGljdWxhcmx5IHRob3NlIGNsb3NlIHRvIE1hbmhhdHRhbiwgZXhoaWJpdCBoaWdoZXIgYmlrZSBzaGFyZSBjb3VudHMsIGxpa2VseSByZWZsZWN0aW5nIGEgaGlnaCB2b2x1bWUgb2YgY29tbXV0ZXJzIHRyYXZlbGluZyBmb3Igd29yaywgc3R1ZHksIG9yIG90aGVyIGRhaWx5IGFjdGl2aXRpZXMuIEFkZGl0aW9uYWxseSwgdGhlc2Ugc3RhdGlvbnMgdGVuZCB0byBoYXZlIHJlbGF0aXZlbHkgbGFyZ2VyIE1lYW4gQWJzb2x1dGUgRXJyb3IgKE1BRSkgdmFsdWVzLCBzaG93aW5nIGEgdGVuZGVuY3kgZm9yIHVuZGVyLXByZWRpY3Rpb24gY29tcGFyZWQgdG8gb3RoZXIgc3RhdGlvbnMuIFRoaXMgc3VnZ2VzdHMgYSBoaWdoIGRlbWFuZCBmb3IgYmlrZXMgaW4gYXJlYXMgbmVhciB0aGUgSHVkc29uIFJpdmVyLiBUbyBhZGRyZXNzIGJpa2UgcmUtYmFsYW5jaW5nIHBsYW4sIGl0IGlzIGVzc2VudGlhbCB0byBlbnN1cmUgdGhhdCBzdGF0aW9ucyBhbnRpY2lwYXRlZCB0byBleHBlcmllbmNlIGhpZ2ggZGVtYW5kIGFyZSBhZGVxdWF0ZWx5IHN1cHBsaWVkIHdpdGggYmlrZXMuIEJhc2VkIG9uIHRoZSBtb2RlbCBhbmFseXNpcywgYWxsb2NhdGluZyBtb3JlIGJpa2VzIHRvIHN0YXRpb25zIG5lYXIgdGhlIEh1ZHNvbiBSaXZlciBpcyBhIG5lY2Vzc2FyeSBzdGVwIHRvIG1lZXQgdGhpcyBkZW1hbmQgZWZmZWN0aXZlbHkuCg==